home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Online / Socks5 / src / server / udp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-10  |  23.6 KB  |  645 lines

  1. /* Copyright (c) 1995-1999 NEC USA, Inc.  All rights reserved.               */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6.  
  7. /*
  8.  * $Id: udp.c,v 1.80.2.1.2.8 1999/02/03 22:35:52 steve Exp $
  9.  */
  10.  
  11. /* This file has all the main functions for handling udp connections.  In    */
  12. /* particular it only one external function which is the main udp function,  */
  13. /* HandleUdpConnection().                                                    */
  14. #include "socks5p.h"
  15. #include "threads.h"
  16. #include "daemon.h"
  17. #include "protocol.h"
  18. #include "validate.h"
  19. #include "udputil.h"
  20. #include "msgids.h"
  21. #include "info.h"
  22. #include "msg.h"
  23. #include "s2s.h"
  24. #include "udp.h"
  25. #include "log.h"
  26.  
  27. #ifndef UDPTIMEOUT
  28. #define UDPTIMEOUT 15*60
  29. #endif
  30.  
  31. #define CODEABLE(x)          ((x) && (x)->auth.encode)
  32. #define CODEBUFF(a, b, c, d) ((a)->auth.encode(b, c, d, (a)->auth.context))
  33.     
  34. #define NEXTADDR(x) (((x)->nextVersion)?&((x)->sckAddr)  :&((x)->dstAddr))
  35. #define NEXTNAME(x) (((x)->nextVersion)? ((x)->sckName): ((x)->dstName))
  36.  
  37. /* Close all the file descriptor, clean up the caches, log the exit error,   */
  38. /* and quit...                                                               */
  39. static void UdpCleanup(S5LinkInfo *pri, UdpInfo *u) {
  40.     S5IOHandle i;
  41.     void *tmp;
  42.  
  43.     if (!u) return;
  44.  
  45.     for (; u->scache ; u->scache = (struct scache *)tmp) {
  46.     S5BufCleanContext(&u->scache->cinfo);
  47.     RemoveIdentEntry(u->scache->idtentry);
  48.     tmp = (void *)u->scache->next;
  49.     free(u->scache);
  50.     }
  51.  
  52.     S5BufCleanContext(&u->iio);
  53.  
  54.     for (i = 0; i < u->maxfd; i++) {
  55.     if (FD_ISSET(i, &u->myfds)) CLOSESOCKET(i);
  56.     }
  57.  
  58.     if (u->relay != S5InvalidIOHandle) CLOSESOCKET(u->relay);
  59.         
  60.     for (; u->acache ; u->acache = (struct acache *)tmp) {
  61.     tmp = (void *)u->acache->next;
  62.     free(u->acache);
  63.     }
  64.  
  65.     for (; u->rcache ; u->rcache = (struct aroute *)tmp) {
  66.     tmp = (void *)u->rcache->next;
  67.     free(u->rcache);
  68.     }
  69.  
  70.     for (; u->hcache; u->hcache = (struct hinfo *)tmp) {
  71.     tmp = (void *)u->hcache->next;
  72.     free(u->hcache);
  73.     }
  74.  
  75.     tmp = (void *)u->sdring->next;
  76.     u->sdring->next = NULL;
  77.     u->sdring = (UdpSdRing *)tmp;
  78.  
  79.     for (; u->sdring; u->sdring = (UdpSdRing *)tmp) {
  80.         tmp = (void *)u->sdring->next;
  81.         free(u->sdring);
  82.     }
  83.     
  84.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_END, "UDP Proxy Termination: (%s:%d) for user %s; %d bytes out %d bytes in",
  85.         pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser, pri->outbc, pri->inbc);
  86.  
  87.     free(u);
  88.     u = NULL;
  89. }
  90.  
  91. /* Process udp use_client_port sub-command.                                  */
  92. static void UdpUseClientPort(S5LinkInfo *pri, UdpInfo *u, u_char *err) {
  93.     /* do we need this ????            */
  94.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Doing USECLIENTPORT command");
  95.  
  96.     if (!lsAddrAddrComp(&pri->dstAddr, &pri->srcAddr) ||
  97.         pri->dstAddr.sin.sin_addr.s_addr == INADDR_ANY ||
  98.         pri->dstAddr.sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
  99.         pri->clientPort = lsAddr2Port(&pri->dstAddr);
  100.         *err = SOCKS5_NOERR;
  101.     }
  102. }
  103.  
  104. /* Process udp bind sub-command.                                             */
  105. static void UdpBind(S5LinkInfo *pri, UdpInfo *u, u_char *err) {
  106.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Doing BIND command");
  107.  
  108.     if (ResolveNames(pri) < 0) return;
  109.  
  110.     if (!lsAddrIsNull(&pri->dstAddr)) {
  111.     *err = SOCKS5_BADADDR;
  112.     return;
  113.     }
  114.  
  115.     if (CheckIfCached(u, pri, 1) == 0) {
  116.        if (u->curs != NULL) {
  117.         if (S5IOCheck(u->curs->cinfo.fd) < 0) return; /* should it re-establish???    */
  118.  
  119.         if (u->curs->reserved != S5UDP_USECTRL) {
  120.         lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr));
  121.             *err = SOCKS5_NOERR;
  122.          return;
  123.         } else {
  124.             if (u->cura->bounded) lsAddrCopy(&pri->intAddr, &u->cura->baddr, sizeof(S5NetAddr));
  125.             else if (S5SExchgUdpCmd(u->curs->cinfo.fd, &u->curs->cinfo, pri, SOCKS5_VERSION, S5UDP_BIND, err) < 0) return;
  126.         }
  127.     } else lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr));
  128.     } else {
  129.         if (CheckIfAllowed(u, pri) < 0) {
  130.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Command: Bind failed: permission denied");
  131.         *err = SOCKS5_AUTHORIZE;
  132.         return;
  133.         }
  134.  
  135.         if (pri->nextVersion == SOCKS5_VERSION && FindProxyEntry(u, pri, &pri->sckAddr, 1) < 0) {
  136.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Command: Couldn't connect to proxy: %s:%d", ADDRANDPORT(&pri->sckAddr));
  137.         return;
  138.         } else if (pri->nextVersion == SOCKS5_VERSION) {
  139.         if (!(pri->nextReserved & S5UDP_USECTRL)) {
  140. /*
  141.                 S5NetAddr na;
  142.                 char msg = '\0';
  143.  
  144.                 lsAddrCopy(&na, &pri->dstAddr, lsAddrSize(&pri->dstAddr));
  145.                 lsAddrSetPort(&na, 9);
  146.                 if (lsUdpProtoSend(pcon->fd, pri, &msg, 1, 0, &na.sa, lsAddrSize(&na)) < 0) return;
  147.  
  148.           lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr));
  149.         *err = SOCKS5_NOERR;
  150. */
  151.          return;
  152.             } else if (S5SExchgUdpCmd(u->curs->cinfo.fd, &u->curs->cinfo, pri, SOCKS5_VERSION, S5UDP_BIND, err) < 0) return;
  153.         } else if (pri->nextVersion != SOCKS5_VERSION) {
  154.         if (FindOutSocket(u, pri, &pri->dstAddr, pri->dstName) == S5InvalidIOHandle) {
  155.                 S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Command: Couldn't make out socket to destination: %s:%d", ADDRANDPORT(&pri->dstAddr));
  156.                 return;
  157.             }
  158.         }
  159.     }
  160.  
  161.     u->cura->bounded = 1;
  162.     lsAddrCopy(&u->cura->baddr, &pri->intAddr, sizeof(S5NetAddr));
  163.     *err = SOCKS5_NOERR;
  164. }
  165.  
  166. /* Process udp getsockname sub-command.                                      */
  167. static void UdpGetsockname(S5LinkInfo *pri, UdpInfo *u, u_char *err) {
  168.  
  169.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Doing GETSOCKNAME command");
  170.  
  171.     if (ResolveNames(pri) < 0) return;
  172.  
  173.     if (!lsAddrIsNull(&pri->dstAddr)) {
  174.     *err = SOCKS5_BADADDR;
  175.     return;
  176.     }
  177.  
  178.     if (CheckIfCached(u, pri, 1) < 0) return;
  179.  
  180.     if (u->curs != NULL) {
  181.     if (u->curs->reserved != S5UDP_USECTRL) return;
  182.     if (S5IOCheck(u->curs->cinfo.fd) < 0) return;
  183.  
  184.         if (u->cura->bounded) lsAddrCopy(&pri->intAddr, &u->cura->baddr, sizeof(S5NetAddr));
  185.         else if (S5SExchgUdpCmd(u->curs->cinfo.fd, &u->curs->cinfo, pri, SOCKS5_VERSION, S5UDP_GETSOCKNAME, err) < 0) return;
  186.     } else lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr));
  187.  
  188.     u->cura->bounded = 1;
  189.     lsAddrCopy(&u->cura->baddr, &pri->intAddr, sizeof(S5NetAddr));
  190.     *err = SOCKS5_NOERR;
  191. }
  192.  
  193. /* Process udp sub-commands received on the tcp control channel.             */
  194. /* Current implementation supports three sub-commands. People should be      */
  195. /* able to add new sub-commands                                              */
  196. static int HandleCommand(S5LinkInfo *pri, UdpInfo *u) {
  197.     u_char cmd = 0, res = 0, s5err = SOCKS5_BADCMND;
  198.  
  199.     memset((char *)&pri->intAddr, 0, sizeof(S5NetAddr));
  200.     pri->intAddr.sa.sa_family = AF_INET;
  201.  
  202.     if (lsReadRequest(u->iio.fd, &u->iio, &pri->dstAddr, &pri->peerVersion, &cmd, &res) < 0) {
  203.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Read request command failed");
  204.         return -1;
  205.     }
  206.  
  207.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Read command (%d) request (%s:%d)", (int)cmd, ADDRANDPORT(&pri->dstAddr));
  208.  
  209.     switch (cmd) {
  210.     case S5UDP_USECLIENTPORT:
  211.         UdpUseClientPort(pri, u, &s5err);
  212.         break;
  213.     case S5UDP_BIND:
  214.         UdpBind(pri, u, &s5err);
  215.         break;
  216.     case S5UDP_GETSOCKNAME:
  217.         UdpGetsockname(pri, u, &s5err);
  218.         break;
  219.     default:
  220.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Unknown command");
  221.         break;
  222.     }
  223.  
  224.     return lsSendResponse(u->iio.fd, &u->iio, &pri->intAddr, pri->peerVersion, s5err, 0, NULL);
  225. }
  226.  
  227. /* Proxy a request for the client.  This basically involves checking to see  */
  228. /* that the information is correct, then checking to see if it is allowed to */
  229. /* send to the destination (in FindOutDestination) as well as finding the    */
  230. /* intermediate destination...If the destination turns out to be directly    */
  231. /* reachable, then we may reassemble a fragment and send that instead.       */
  232. /*                                                                           */
  233. /* Arguments: sin -- the address of the person who sent the message to us    */
  234. static int RecvFromClient(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, S5NetAddr *sender) {
  235.     S5Packet buf[2];
  236.  
  237.     /* Make sure the client really sent this message.  If not, assume it is  */
  238.     /* a forgery.                                                            */
  239.     if (lsAddrComp(&pri->srcAddr, sender)) {
  240.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Client Receive: Received message from non-client (%s:%d) on client socket", ADDRANDPORT(sender));
  241.         return -1;
  242.     }
  243.  
  244.     /* Decode the message and copy the decode message into u->obuf.          */
  245.     if (CODEABLE(&u->iio)) {
  246.     buf[0].data = u->obuf; buf[0].len = u->obuflen; buf[0].off = u->obuflen;
  247.     buf[1].data = NULL;    buf[1].len = 0;        buf[1].off = 0;
  248.     
  249.     if (CODEBUFF(&u->iio, &buf[0], &buf[1], S5_DECODE) < 0 || buf[1].len > UDP_MAX_PAYLOAD) {
  250.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Client Receive: Error decoding message");
  251.         return -1;
  252.     } else {
  253.         memcpy(u->obuf, buf[1].data, buf[1].len);
  254.         u->obuflen = buf[1].len;
  255.         free(buf[1].data);
  256.     }
  257.     }
  258.  
  259.     /* A real message would have to have a length greater than the header    */
  260.     /* size.  Drop the message if it does not.                               */
  261.     if (u->obuflen <= MINHDRSIZE) {
  262.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Client Receive: Received invalid message from client: too short");
  263.     return -1;
  264.     }
  265.  
  266.     /* Extract the destination address and it's name.                        */
  267.     if (lsGetProtoAddr(SOCKS5_VERSION, u->obuf, &pri->dstAddr) < 0) {
  268.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Client Receive: Received invalid message from client: invalid address");
  269.     return -1;
  270.     } 
  271.  
  272.     if (ResolveNames(pri) < 0) {
  273.     return -1;
  274.     }
  275.  
  276.     /* Make sure we've either talked to this destination before, or we are   */
  277.     /* allowed to talk to it...                                              */
  278.     if (CheckIfCached(u, pri, 1) < 0 && CheckIfAllowed(u, pri) < 0) {
  279.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Client Receive: send failed: permission denied");
  280.     return -1;
  281.     }
  282.  
  283.     packet->data = u->obuf    + HDRSIZE(u->obuf);
  284.     packet->off  = u->obuflen - HDRSIZE(u->obuf);
  285.     packet->len  = UDP_MAX_PAYLOAD;
  286.  
  287.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Client Receive: Received valid message of length %d", u->obuflen-HDRSIZE(u->obuf));
  288.     return u->obuflen - HDRSIZE(u->obuf);
  289. }
  290.  
  291. /* Proxy a request back from a server. This basically involves checking to   */
  292. /* see if this is from a server we've talked to (FindCachedSocks) in which   */
  293. /* case we forward it on... If not, it was from the application server.      */
  294. /* To handle this case, we first check that this server is allowed (cache?)  */
  295. /* then, if it is, package it up (possibly fragmenting it) and ship it back  */
  296. /* to the client.                                                            */
  297. /*                                                                           */
  298. /* Arguments: sin -- the address of the person who sent the message to us    */
  299. static int RecvFromServer(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, S5NetAddr *sender) {
  300.     S5Packet buf[2];
  301.     
  302.     /* If we don't find a proxy entry, zero out the appropriate structures   */
  303.     /* so that when we look at them later, we don't do something wrong.  If  */
  304.     /* we did find one, go ahead and look up its name for logging...         */
  305.     pri->dstAddr = *sender;
  306.     if (FindProxyEntry(u, pri, &pri->dstAddr, 0) < 0) {
  307.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: Received message from dead server");
  308.     return -1;
  309.     }
  310.  
  311.     /* If we have a decode function for the server, go ahead and decode the  */
  312.     /* message and move it into the appropriate place                        */
  313.     if (CODEABLE(u->oiop)) {
  314.     buf[0].data = u->obuf; buf[0].len = u->obuflen; buf[0].off = u->obuflen;
  315.     buf[1].data = NULL;    buf[1].len = 0;        buf[1].off = 0;
  316.  
  317.     if (CODEBUFF(u->oiop, &buf[0], &buf[1], S5_DECODE) < 0 || buf[1].len > UDP_MAX_PAYLOAD) {
  318.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: Error decoding message from server");
  319.         return -1;
  320.     } else {
  321.         memcpy(u->obuf, buf[1].data, buf[1].len);
  322.         u->obuflen = buf[1].len;
  323.         free(buf[1].data);
  324.     }
  325.     }
  326.  
  327.     /* If FindProxyEntry told us this was from another socks server, strip   */
  328.     /* off the header that it put on the message...                          */
  329.     if (pri->nextVersion == SOCKS5_VERSION) {
  330.     if (lsGetProtoAddr(SOCKS5_VERSION, u->obuf, &pri->dstAddr) < 0) {
  331.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: Received invalid message from server: invalid address");
  332.         return -1;
  333.     } 
  334.  
  335.     u->obuflen -= HDRSIZE(u->obuf);
  336.     u->obuf    += HDRSIZE(u->obuf);
  337.     }
  338.  
  339.     GetName(pri->dstName, &pri->dstAddr);
  340.  
  341.     /* Make sure we've talked to the sender before.  If not, we will ignore  */
  342.     /* this reply, assuming that this is a forgery.                          */
  343.     if (CheckIfCached(u, pri, 1) < 0 && CheckIfAllowed(u, pri) < 0) {
  344.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: recv failed: permission denied");
  345.         return -1;
  346.     }
  347.  
  348.     packet->data = u->obuf;
  349.     packet->len  = UDP_MAX_PAYLOAD;
  350.     packet->off  = u->obuflen;
  351.  
  352.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "UDP Server Receive: Received valid message of length %d", u->obuflen);
  353.     return u->obuflen;
  354. }
  355.  
  356. int UdpRecvPkt(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, int *dir) {
  357.     S5IOHandle maxfd;
  358.     fd_set fds;
  359.     UdpSdRing *sr;
  360.     int rval;
  361.     
  362.     for (;;) {
  363.     struct timeval inact = { UDPTIMEOUT, 0 };
  364.     
  365.     if (*dir & S5_DIRECTION_IN) {
  366.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "UDP Receive: Selecting on outer sockets...");
  367.         maxfd = u->maxfd;
  368.         fds = u->myfds;
  369.     } else {
  370.         maxfd = 0;
  371.         FD_ZERO(&fds);
  372.     }
  373.     
  374.     if (*dir & S5_DIRECTION_OUT) {
  375.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "UDP Receive: Selecting on inner socket...");
  376.         FD_SET(u->relay, &fds);
  377.         maxfd = MAX(maxfd, u->relay);
  378.     }
  379.  
  380.     FD_SET(u->iio.fd, &fds);    
  381.     maxfd = MAX(maxfd, u->iio.fd);
  382.  
  383.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "UDP Receive: Selecting...");
  384.  
  385.     switch (select(maxfd+1, &fds, NULL, NULL, &inact)) {
  386.         case 0:
  387.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Receive: Inactivity timeout expired");
  388.         rval = -1;
  389.         goto end;
  390.         case -1:
  391.         if (ISSOCKETERROR(EINTR)) continue;
  392.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Receive: select failed: %m");
  393.         rval = -1;
  394.         goto end;
  395.     }
  396.     
  397.     if (FD_ISSET(u->iio.fd, &fds)) {
  398.             if (S5IOCheck(u->iio.fd) < 0) rval = 0;
  399.         else if ((pri->peerReserved & S5UDP_USECTRL) && !HandleCommand(pri, u)) continue;
  400.         else {
  401.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Receive: client closed connection");
  402.             rval = -1;
  403.         }
  404.  
  405.         goto end;
  406.     }
  407.         
  408.         if (u->sdring) u->sdring = u->sdring->next;
  409.         for (sr = u->sdring;sr;sr = (u->sdring==sr->next)?NULL:sr->next) {
  410.             int fromlen = sizeof(S5NetAddr);
  411.             S5NetAddr sender;
  412.         
  413.         if (!FD_ISSET(sr->sd, &fds)) continue;
  414.  
  415.         u->obuf    = u->mbuf         + MAXHDRSIZE;
  416.         u->obuflen = sizeof(u->mbuf) - MAXHDRSIZE;
  417.         
  418.         while ((u->obuflen = recvfrom(sr->sd, u->obuf, u->obuflen, 0, (ss *)&sender, &fromlen)) < 0 && ISSOCKETERROR(EINTR));
  419.  
  420.         if (u->obuflen < 0) {
  421.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Receive: real recvfrom failed: %m");
  422.         rval = -1;
  423.         goto end;
  424.         }
  425.         
  426.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Receive: received a message from %s:%d", ADDRANDPORT(&sender));
  427.  
  428.         if (sr->sd == u->relay) {
  429.         if ((rval = RecvFromClient(packet, pri, u, &sender)) <= 0) continue; 
  430.         *dir = S5_DIRECTION_OUT;
  431.         } else {
  432.             if ((rval = RecvFromServer(packet, pri, u, &sender)) <= 0) continue;
  433.             *dir = S5_DIRECTION_IN;
  434.         }
  435.  
  436.         goto end;
  437.     }
  438.     }
  439.  
  440.   end:
  441.     if (rval <= 0) {
  442.     packet->data = NULL;
  443.     packet->off  = 0;
  444.     packet->len  = 0;
  445.     }
  446.     
  447.     return rval;
  448. }
  449.     
  450. int UdpSendPkt(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, int *dir) {
  451.     S5Packet buf[2];
  452.     S5NetAddr *dst;
  453.     S5IOInfo *info;
  454.     S5IOHandle fd;
  455.     int alen;
  456.  
  457.     if (packet->data < u->mbuf + MAXHDRSIZE ||
  458.     packet->data > u->mbuf + MAXHDRSIZE + UDP_MAX_PAYLOAD ) {
  459.     char *tmp;
  460.  
  461.     if ((tmp = (char *)malloc(packet->off)) == NULL) {
  462.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP send: Malloc failed.");
  463.         u->obuflen = -1;
  464.         goto end;
  465.     }
  466.     
  467.     memcpy(tmp, packet->data, packet->off);
  468.     u->obuf    = u->mbuf      + MAXHDRSIZE;
  469.     u->obuflen = packet->off;
  470.     memcpy(u->obuf, tmp, u->obuflen);
  471.     free(tmp);
  472.     } else {
  473.     u->obuf    = packet->data;
  474.     u->obuflen = packet->off;
  475.     }
  476.     
  477.     if (*dir == S5_DIRECTION_IN) {
  478.     dst  = &pri->srcAddr;
  479.     fd   = u->relay;
  480.     info = &u->iio;
  481.     } else {
  482.     /* If we'll be using a proxy and we haven't talked to it yet,        */
  483.     /* initialize the connection and add it it list of know proxies...   */
  484.     if (pri->nextVersion == SOCKS5_VERSION && FindProxyEntry(u, pri, &pri->sckAddr, 1) < 0) {
  485.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP send: Couldn't connect to %s:%d", ADDRANDPORT(&pri->sckAddr));
  486.         u->obuflen = -1;
  487.         goto end;
  488.     }
  489.  
  490.     /* Find out how we should go out, update the byte count, and dump    */
  491.     /* the packet if need be.                                            */
  492.     fd   = FindOutSocket(u, pri, NEXTADDR(pri), NEXTNAME(pri));
  493.     dst  = NEXTADDR(pri);
  494.     info = u->oiop;
  495.     }
  496.  
  497.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Sending to %s:%d", ADDRANDPORT(dst));
  498.  
  499.     if (*dir == S5_DIRECTION_IN || pri->nextVersion == SOCKS5_VERSION) {
  500.     if ((alen = lsGetProtoAddrLenFromAddr(SOCKS5_VERSION, &pri->dstAddr)) < 0) {
  501.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Error filling in address in packet header");
  502.         u->obuflen = -1;
  503.         goto end;
  504.     }
  505.  
  506.     u->obuf -= alen;
  507.     memset(u->obuf, 0, 3);
  508.     lsSetProtoAddr(SOCKS5_VERSION, u->obuf, &pri->dstAddr);
  509.     u->obuflen += HDRSIZE(u->obuf);
  510.     }
  511.     
  512.     /* Encode the packet if necessary... This includes changing obuf to      */
  513.     /* point to the buffer that the encoding creates.  We'll free that       */
  514.     /* buffer later if need be.                                              */
  515.     if (CODEABLE(info)) {
  516.     
  517.     buf[0].data = u->obuf;
  518.     buf[0].len  = u->obuflen;
  519.     buf[0].off  = 0;
  520.  
  521.     buf[1].data = NULL;
  522.     buf[1].len = 0;
  523.     buf[1].off = 0;
  524.     
  525.     if (CODEBUFF(info, &buf[0], &buf[1], S5_ENCODE) < 0) {
  526.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Error encoding message for client");
  527.         u->obuflen = -1;
  528.         goto end;
  529.     } else {
  530.         u->obuf    = buf[1].data;
  531.         u->obuflen = buf[1].len;
  532.     }
  533.     }
  534.  
  535.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Sending a message of length %d", u->obuflen);
  536.  
  537.     /* Send the message and log the fact that we have.                       */
  538.     if (sendto(fd, u->obuf, u->obuflen, 0, &dst->sa, sizeof(ssi)) < 0) {
  539.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Sendto failed: %m");
  540.     } else if (*dir == S5_DIRECTION_OUT) {
  541.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Client Sent Message to %s:%d", ADDRANDPORT(dst));
  542.     } else {
  543.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Client Recveived Message from %s:%d", ADDRANDPORT(&pri->dstAddr));
  544.     }
  545.  
  546.     /* Free any space we had to allocate because of the encoding             */
  547.     if (CODEABLE(info)) {
  548.     if (buf[1].data) free(buf[1].data);
  549.     }
  550.  
  551.   end:
  552.     packet->data = NULL;
  553.     packet->off  = 0;
  554.     packet->len  = 0;
  555.     return u->obuflen;
  556. }
  557.  
  558. int UdpSetup(S5IOInfo *ioinfo, S5LinkInfo *pri, S5CommandInfo *cmdinfo) {
  559.     int len = sizeof(S5NetAddr), rval = EXIT_ERR;
  560.     S5NetAddr route;
  561.     u_char s5err = SOCKS5_FAIL;
  562.     UdpInfo *u = NULL;
  563.     
  564.     /* The destination is really the port we'll be receiving request from    */
  565.     /* it is allowed to be 0, but we take that to mean we'll be recv'ing it  */
  566.     /* from the same place the tcp connection came from, different port      */
  567.     if (lsAddrAddrComp(&pri->dstAddr, &pri->srcAddr) != 0) {
  568.     if (pri->dstAddr.sin.sin_addr.s_addr != INADDR_ANY && pri->dstAddr.sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
  569.         s5err = SOCKS5_BADADDR;
  570.         goto cleanup;
  571.     }
  572.     }
  573.  
  574.     /* Allocate space for the udp specific options we'll be using...         */
  575.     if (!(cmdinfo->option = (void *)(u = (UdpInfo *)calloc(1, sizeof(UdpInfo))))) {
  576.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Setup: Malloc() failed");
  577.     goto cleanup;
  578.     }
  579.  
  580.     u->sdring = NULL;
  581.  
  582.     u->iio  = *ioinfo;
  583.     memset(&u->myfds, 0, sizeof(fd_set));
  584.  
  585.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_START, "UDP Proxy Request: (%s:%d) for user %s", pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser);
  586.  
  587.     /* if the destination port is 0, we will assume the same port as tcp's    */
  588.     if (lsAddr2Port(&pri->dstAddr) != (u_short)0) lsAddrSetPort(&pri->srcAddr, lsAddr2Port(&pri->dstAddr));
  589.  
  590.     /* We set the destination address same as the source for Authorize        */
  591.     /* function to distinguish the UDP request and UDP messages ...           */
  592.     lsAddrCopy(&pri->dstAddr, &pri->srcAddr, lsAddrSize(&pri->srcAddr));
  593.     if (Authorize(pri, 0) != AUTH_OK) {
  594.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: Setup failed: permission denied");
  595.     s5err = SOCKS5_AUTHORIZE;
  596.     rval  = EXIT_AUTH;
  597.     goto cleanup;
  598.     }
  599.  
  600.     lsAddrCopy(&route, &pri->bndAddr, lsAddrSize(&pri->bndAddr));
  601.     lsAddrSetPort(&route, (u_short)0);
  602.  
  603.     if ((u->relay = MakeOutSocket(u, &route, (u_short)0)) == S5InvalidIOHandle) {
  604.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: Couldn't make main udp socket: %m");
  605.     goto cleanup;
  606.     }
  607.  
  608.     if (getsockname(u->relay, (ss *)&route.sa, &len) < 0) {
  609.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: Getsockname failed on main udp socket: %m");
  610.     goto cleanup;
  611.     }
  612.  
  613.     lsAddrSetPort(&pri->bndAddr, lsAddr2Port(&route));
  614.  
  615.     if (lsSendResponse(u->iio.fd, &u->iio, &pri->bndAddr, pri->peerVersion, SOCKS5_RESULT, (pri->peerReserved & S5UDP_USECTRL)?S5UDP_USECTRL:0, NULL) < 0) {
  616.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: couldn't send response");
  617.     rval = EXIT_NETERR;
  618.     goto cleanup;
  619.     }
  620.  
  621.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_ESTAB, "UDP Proxy Established: (%s:%d) for user %s",
  622.         pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser);
  623.  
  624.     cmdinfo->recvpkt  = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))UdpRecvPkt;
  625.     cmdinfo->sendpkt  = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))UdpSendPkt;
  626.     cmdinfo->clean    = (int (*)(S5LinkInfo *, void *))UdpCleanup;
  627.     return EXIT_OK;
  628.  
  629.   cleanup:
  630.     if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &pri->bndAddr, pri->peerVersion, s5err, 0, NULL);
  631.  
  632.     if (u != NULL) UdpCleanup(pri, u);
  633.     else {
  634.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_END, "UDP Proxy Termination: (%s:%d) for user %s; %d bytes out %d bytes in",
  635.                 pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser, pri->outbc, pri->inbc);
  636.  
  637.         S5BufCleanContext(ioinfo);
  638.     }
  639.  
  640.     /* Prevent any further problems from being seg faults.                   */
  641.     cmdinfo->option = NULL;
  642.     if (rval == EXIT_OK) rval = EXIT_ERR;
  643.     return rval;
  644. }
  645.